package com.ecr.hub.database.dao.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.ecr.hub.database.dao.IDaoRail;
import com.ecr.hub.database.mapper.MapperRail;
import com.ecr.hub.model.enumeration.HubObjectActive;
import com.ecr.hub.model.rail.Rail;
import com.ecr.hub.model.rail.TypeBundle;

@Repository("daoRail")
public class DaoRailImpl extends MapperRail implements IDaoRail {

	// Récupération de l'ensemble des voies.
	private static final String REQ_SELECT_ALL = "SELECT rail.id, rail.number, rail.label, rail.util_lenght, rail.electric_traction, "
			+ "rail.assignment, rail.comment, rail.destination_id, rail.destination_label, rail.destination_hex_color, "
			+ "rail.active, rail.available, rail.sort_order, bundle.id as bundle_id, bundle.label as bundle_label "
			+ "FROM hub_rail as rail, hub_bundle_type as bundle WHERE rail.bundle_type_id=bundle.id";

	// Récupération d'une voie en fonction de son identifiant.
	private static final String REQ_SELECT_BY_ID = REQ_SELECT_ALL
			+ " AND rail.id=?";

	// Récupération d'un sous-groupe des voies (actives).
	private static final String REQ_SELECT_BY_TYPE_BUNDLE = REQ_SELECT_ALL
			+ " AND rail.bundle_type_id=? AND rail.active="
			+ HubObjectActive.ACTIVE.getValue()
			+ " ORDER BY bundle.sort_order, rail.sort_order ASC";

	// Récupération d'un sous-groupe des voies (actives et non actives).
	private static final String REQ_SELECT_ALL_BY_TYPE_BUNDLE = REQ_SELECT_ALL
			+ " AND rail.bundle_type_id=?"
			+ " ORDER BY bundle.sort_order, rail.sort_order ASC";

	// Récupération de l'ensemble des voies actives.
	private static final String REQ_SELECT_ALL_ACTIVE = REQ_SELECT_ALL
			+ " AND rail.active=" + HubObjectActive.ACTIVE.getValue()
			+ " ORDER BY bundle.sort_order, rail.sort_order ASC";

	// Récupération des différents types de faisceaux.
	private static final String REQ_SELECT_TYPE_BUNDLE = "SELECT * FROM hub_bundle_type";

	// Mise à jour d'une voie.
	private static final String REQ_UPDATE = "UPDATE hub_rail SET label=?, comment=?, assignment=?, "
			+ "destination_id=?, destination_label=?, destination_hex_color=?, active=?, available=? WHERE id=?";

	// Mise à jour d'une voie uniquement pour la rendre disponible ou
	// indisponible.
	private static final String REQ_UPDATE_AVAILABLE = "UPDATE hub_rail SET available=? WHERE id=?";

	// Récupération des voies en fonction de la destination affectée à la voie.
	private static final String REQ_SELECT_BY_DESTINATION = REQ_SELECT_ALL
			+ " AND rail.destination_id=?";

	// Mise à jour des voies en fonction de la destination affectée à la voie.
	private static final String REQ_UPDATE_FOR_DESTINATION = "UPDATE hub_rail SET destination_label=?, "
			+ "destination_hex_color=? WHERE id=?";

	@Autowired
	JdbcTemplate jdbcTemplate;

	/**
	 * Récupération de la liste des voies. On prend l'ensemble des
	 * enregistrements dans la table hub_rail avec une liaison sur ceux de la
	 * table hub_bundle_type. Pour éviter des requêtes avec des OUTER JOIN, on
	 * récupère dans cette table les informations basiques sur les destinations.
	 */
	@Override
	public List<Rail> getAllList() throws DataAccessException {

		return jdbcTemplate.query(REQ_SELECT_ALL, mapperRail);
	}

	/**
	 * Mise à jour de la table des voies. Modification de l'enregistrement dans
	 * la table hub_rail.
	 */
	@Override
	@Transactional
	public void update(Rail rail) throws DataAccessException {

		jdbcTemplate.update(
				REQ_UPDATE,
				new Object[] { rail.getLabel(), rail.getComment(),
						rail.getAssignment(), rail.getDestinationId(),
						rail.getDestinationLabel(),
						rail.getDestinationHexColor(), rail.isActive(),
						rail.isAvailable(), rail.getId() });
	}

	/**
	 * Récupération de la liste des types de faisceaux. Récupération de
	 * l'ensemble des enregistrements dans la table hub_bundle_type.
	 */
	@Override
	public List<TypeBundle> getListTypeBundle() throws DataAccessException {

		return jdbcTemplate.query(REQ_SELECT_TYPE_BUNDLE, mapperBundle);
	}

	/**
	 * Récupération de la liste des voies en fonction filtrée par le type de
	 * faisceau.
	 */
	@Override
	public List<Rail> getListByTypeBundle(int id, int active)
			throws DataAccessException {

		List<Rail> lstRails;
		if (active == HubObjectActive.ALL.getValue()) {
			lstRails = jdbcTemplate.query(REQ_SELECT_ALL_BY_TYPE_BUNDLE,
					mapperRail, new Object[] { id });
		} else {
			lstRails = jdbcTemplate.query(REQ_SELECT_BY_TYPE_BUNDLE,
					mapperRail, new Object[] { id });
		}
		return lstRails;
	}

	/**
	 * Liste l'ensemble des voies actives pour affichage sur le panneau central
	 * du Hub. On prend l'ensemble des voies dans la table hub_rail dont le
	 * booleen "active" est à "true".
	 */
	@Override
	public List<Rail> getListForHub() throws DataAccessException {

		return jdbcTemplate.query(REQ_SELECT_ALL_ACTIVE, mapperRail);
	}

	/**
	 * Méthode qui rend juste la voie disponible ou indisponible. Comme cette
	 * méthode va servir de nombreuses fois par jour, il est plus propre de ne
	 * pas passer par la méthode de mise à jour globale (update).
	 */
	@Override
	@Transactional
	public void updateForAvailable(Rail rail) throws DataAccessException {

		jdbcTemplate.update(REQ_UPDATE_AVAILABLE,
				new Object[] { rail.isAvailable(), rail.getId() });
	}

	/**
	 * Mise à jour des enregistrements qui contiennent des informations sur une
	 * destination qui a été modifiée. Comme on recopie directement certaines
	 * informations des destinations dans l'objet voie, si une destination est
	 * modifiée, il faut reporter les impacts sur la voie.
	 */
	@Override
	@Transactional
	public void updateForDestination(int id, String label, String hexColor)
			throws DataAccessException {
		List<Rail> lstRails = jdbcTemplate.query(REQ_SELECT_BY_DESTINATION,
				mapperRail, new Object[] { id });
		for (Rail rail : lstRails) {
			rail.setDestinationHexColor(hexColor);
			rail.setDestinationLabel(label);
			jdbcTemplate.update(
					REQ_UPDATE_FOR_DESTINATION,
					new Object[] { rail.getDestinationLabel(),
							rail.getDestinationHexColor(), rail.getId() });
		}
	}

	/**
	 * Récupération de des informations d'une voie à partir de l'identifiant
	 * interne de la voie.
	 */
	@Override
	public Rail getById(int id) throws DataAccessException {

		Rail rail = jdbcTemplate.queryForObject(REQ_SELECT_BY_ID, mapperRail,
				new Object[] { id });
		return rail;
	}

	/**
	 * Récupération des voies qui sont attachées à une destination particulière.
	 * Cette méthode est juste utilisée lors de la demande de suppression d'une
	 * destination, pour contrôler que la destination n'est plus rattachée à une
	 * voie.
	 */
	@Override
	public List<Rail> getByDestinationId(int id) throws DataAccessException {

		return jdbcTemplate.query(REQ_SELECT_BY_DESTINATION, mapperRail,
				new Object[] { id });
	}
}
